﻿using System;
using System.Collections;
using System.Threading;
using Flight.Controller.Entities;
using FlightController;
using Microsoft.SPOT;

namespace Flight.Controller.Managers
{
    /// <summary>
    /// Singleton to handle flight actions.
    /// </summary>
    public class FlightManager
    {
        private static FlightManager _Instance;

        private ILogger _logger;
        private BaseController _controller;
        private bool _stop = false;
        private Queue _actionQueue = new Queue();

        public event System.AsyncCallback FlightActionCompleted;

        private FlightManager(BaseController ctrl, ILogger logger)
        {
            _controller = ctrl;
            _logger = logger;
            new Thread(new ThreadStart(Run)) { Priority = ThreadPriority.Highest }.Start();
        }

        /// <summary>
        /// Gets the message logger.
        /// </summary>
        public ILogger Logger
        {
            get
            {
                return _logger;
            }
        }

        private void Run()
        {
            while (!_stop)
            {
                lock (_actionQueue)
                {
                    if (_actionQueue.Count == 0)
                        continue;

                    FlightAction a = (FlightAction)_actionQueue.Dequeue();
                    FlightActionResult result = new FlightActionResult();

                    try
                    {
                        _logger.Log(a.ToString());

                        switch (a.Move)
                        {
                            case FlightActionMove.PITCH: _controller.DoPitch(a.Value, a.Speed);
                                break;
                            case FlightActionMove.ROLL: _controller.DoRoll(a.Value, a.Speed);
                                break;
                            case FlightActionMove.YAW: _controller.DoYaw(a.Value, a.Speed);
                                break;
                            case FlightActionMove.ALTITUDE: _controller.SetAltitude((ushort)a.Value, a.Speed);
                                break;
                            case FlightActionMove.STABILIZE: _controller.Stabilize();
                                break;
                            default: throw new NotSupportedException("Move type is not supported!");
                        }
                    }
                    catch (FlightFailureException fex)
                    {
                        _logger.Log(fex);
                        _controller.LaunchParachute();
                        _stop = true;
                        result.HasFail = true;
                    }
                    catch (Exception ex)
                    {
                        _logger.Log(ex);
                        result.HasFail = true;
                    }

                    if (FlightActionCompleted != null)
                        FlightActionCompleted(result);
                }

                Thread.Sleep(5);
            }
        }

        public static void InitializeManager(BaseController ctrl, ILogger logger)
        {
            _Instance = new FlightManager(ctrl, logger);
        }

        public static void AddAction(FlightAction action)
        {
            lock (_Instance._actionQueue)
            {
                _Instance._actionQueue.Enqueue(action);
            }
        }

        public static void StopManager()
        {
            _Instance._stop = true;
        }
    }
}
